package com.easylinkin.linkappapi.airconditioner.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easylinkin.linkappapi.airconditioner.entity.AirHostDevice;
import com.easylinkin.linkappapi.airconditioner.entity.AirconditionDevice;
import com.easylinkin.linkappapi.airconditioner.mapper.AirHostDeviceMapper;
import com.easylinkin.linkappapi.airconditioner.service.AirHostDeviceService;
import com.easylinkin.linkappapi.airconditioner.service.AirconditionDeviceService;
import com.easylinkin.linkappapi.common.utils.excel.ExcelConstant;
import com.easylinkin.linkappapi.common.utils.excel.ExcelReadUtil;
import com.easylinkin.linkappapi.common.utils.excel.ExcelTools;
import com.easylinkin.linkappapi.common.utils.io.OutputStreamUtil;
import com.easylinkin.linkappapi.device.entity.Device;
import com.easylinkin.linkappapi.device.service.DeviceService;
import com.easylinkin.linkappapi.elasticsearch.entity.ESconfig;
import com.easylinkin.linkappapi.security.context.LinkappUserContextProducer;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.web.multipart.MultipartFile;

@Service
public class AirHostDeviceServiceImpl extends ServiceImpl<AirHostDeviceMapper, AirHostDevice> implements AirHostDeviceService{
    private static final int PARSE_EXCEL_START_ROW = 1;
    private static final int CONTENT_IN_EXCEL_START_ROW = 1;
    private static final Logger LOGGER = LoggerFactory.getLogger(AirHostDeviceServiceImpl.class);
    @Resource
    DeviceService deviceService;
    @Resource
    AirconditionDeviceService airconditionDeviceService;
    @Resource
    private LinkappUserContextProducer linkappUserContextProducer;
    private ESconfig eSconfig;
    @Autowired
    public void setESconfig(ESconfig eSconfig) {
        this.eSconfig = eSconfig;
    }

    @Override
    public List<AirHostDevice> getAll() {
        String tenantId=linkappUserContextProducer.getNotNullCurrent().getTenantId();
        QueryWrapper<AirHostDevice> qw=new QueryWrapper<>();
        qw.eq("tenant_id",tenantId);
        qw.select("device_id","device_code","device_name","wattmeter_id","switch_state");
        qw.orderByDesc("update_time");
        return baseMapper.selectList(qw);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchInsert(List<AirHostDevice> list) {
       if(list == null || list.size()<=0){
           return;
       }
       String tenantId=linkappUserContextProducer.getNotNullCurrent().getTenantId();
       List<String> ids=list.stream().map(i->i.getDeviceId()).collect(Collectors.toList());
       QueryWrapper<Device> qwd=new QueryWrapper<>();
       qwd.in("code",ids);
       qwd.eq("tenant_id",tenantId);
       List<Device> deviceList=deviceService.list(qwd);
       Assert.notEmpty(deviceList,"设备"+JSON.toJSONString(ids)+"不存在");
        //求差集
        if(deviceList.size() != ids.size()){
          List<String> deviceCodes=deviceList.stream().map(i->i.getCode()).collect(Collectors.toList());
          List<String> filterIds=ids.stream().filter(item->!deviceCodes.contains(item)).collect(Collectors.toList());
          if(filterIds.size()>0){
              Assert.isTrue(false,"设备"+JSON.toJSONString(filterIds)+"不存在");
          }
         //交集
            filterIds=ids.stream().filter(item->deviceCodes.contains(item)).collect(Collectors.toList());
          if(filterIds.size()>0){
              Assert.isTrue(false,"设备"+JSON.toJSONString(filterIds)+"已绑定");
          }
        }
        QueryWrapper<AirHostDevice> qw=new QueryWrapper<>();
        qw.in("device_id",ids);
        qw.eq("tenant_id",tenantId);
        List<AirHostDevice> airHostDeviceList=baseMapper.selectList(qw);
        if(airHostDeviceList != null && airHostDeviceList.size()>0){
            //求交集
            List<String> hostIds=airHostDeviceList.stream().map(i->i.getDeviceId()).collect(Collectors.toList());
            List<String> filterIds=ids.stream().filter(item->hostIds.contains(item)).collect(Collectors.toList());
            if(filterIds.size()>0){
                Assert.isTrue(false,"设备"+JSON.toJSONString(filterIds)+"已绑定");
            }
        }
        //批量添加
        Date date=new Date();
        list=list.stream().map(i->{i.setCreateTime(date);i.setUpdateTime(date);i.setTenantId(tenantId);return i;}).collect(Collectors.toList());
        baseMapper.batchInsert(list);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void remove(AirHostDevice airHostDevice) {
        Assert.notNull(airHostDevice,"参数为空!");
        Assert.notNull(airHostDevice.getDeviceId(),"参数为空!");
        String tenantId=linkappUserContextProducer.getNotNullCurrent().getTenantId();
        QueryWrapper<AirHostDevice> qw=new QueryWrapper<>();
        qw.eq("tenant_id",tenantId);
        qw.eq("device_id",airHostDevice.getDeviceId());
        baseMapper.delete(qw);
    }

    @Override
    public void getImportTemplate(HttpServletRequest request, HttpServletResponse response) {
        String title = "主机批量导入模板";
        String fileName = title + ".xls";
        try {
            OutputStream outputStream = OutputStreamUtil
                    .getOutputStream(request, response, fileName);
            String keyValue = "主机编码(必填):deviceId,电表编码(必填):wattmeterId";
            ExcelTools
                    .exportExcel(outputStream, keyValue, new ArrayList<AirHostDevice>(), ExcelConstant.XLS,
                            title);
            response.flushBuffer();
            outputStream.close();
        } catch (IOException e) {
            LOGGER.error("excel导出失败", e);
            throw new RuntimeException("excel导出失败！IOException异常");
        } catch (Exception e) {
            LOGGER.error("excel导出失败", e);
            throw new RuntimeException("excel导出失败！");
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Set importData(MultipartFile file) {
        Set deviceErrorList = new HashSet();
        List<AirHostDevice> list = getImportData(getContentList(file), deviceErrorList);
        if(list != null && list.size()>0){
            baseMapper.batchInsert(list);
        }
        return deviceErrorList;
    }

    @Override
    public AirHostDevice getById(String deviceId){
        //检查主机表是否存在
        QueryWrapper<AirHostDevice> qw=new QueryWrapper<>();
        qw.eq("device_id",deviceId);
        String tenantId=linkappUserContextProducer.getNotNullCurrent().getTenantId();
        qw.eq("tenant_id",tenantId);
        return baseMapper.selectOne(qw);
    }

    /***
     * 根据ID查询是否存在
     * @param deviceId
     * @return
     */
    private AirHostDevice getAirHostDeviceIfExists(String deviceId,String tenantId){
        if(org.springframework.util.StringUtils.isEmpty(deviceId)){
            return null;
        }
        //检查设备表是否存在
        QueryWrapper<Device> qwDevice=new QueryWrapper<>();
        qwDevice.eq("code",deviceId);
        qwDevice.eq("tenant_id",tenantId);
        Device device=deviceService.getOne(qwDevice);
        if(device == null){
            return null;
        }
        //检查主机表是否存在
        QueryWrapper<AirHostDevice> qw=new QueryWrapper<>();
        qw.eq("device_id",deviceId);
        qw.eq("tenant_id",tenantId);
        Integer count=baseMapper.selectCount(qw);
        if(count>0){
           return null;
        }
        AirHostDevice airHostDevice=new AirHostDevice();
        airHostDevice.setDeviceId(device.getId());
        airHostDevice.setDeviceCode(device.getCode());
        airHostDevice.setDeviceName(device.getName());
        return airHostDevice;
    }

    private List<AirHostDevice> getImportData(List<List<String>> contentList, Set deviceErrorList) {
        AirHostDevice device;
        String value;
        List<AirHostDevice> devices = new ArrayList<>();
        Date date=new Date();
       String  tenantId=linkappUserContextProducer.getNotNullCurrent().getTenantId();
        for (int row = CONTENT_IN_EXCEL_START_ROW; row < contentList.size(); row++) {
            try {
                boolean loop = true;
                device = new AirHostDevice();
                for (int i = 0; i < contentList.get(row).size() && loop; i++) {
                    value = StringUtils.isEmpty(contentList.get(row).get(i))
                            || StringUtils.isEmpty(contentList.get(row).get(i).trim())
                            ? null : contentList.get(row).get(i).trim();
                    switch (i) {
                        case 0:
                            AirHostDevice airHostDevice = getAirHostDeviceIfExists(value,tenantId);
                            if (airHostDevice != null) {
                                device.setDeviceId(value);
                                device.setDeviceName(airHostDevice.getDeviceName());
                                device.setDeviceCode(airHostDevice.getDeviceCode());
                            } else {
                                deviceErrorList.add(row);
                                loop = false;
                            }
                            break;
                        case 1:
                           Integer count=getWattmeterBindIfExists(value,tenantId);
                            if (count != null) {
                                device.setWattmeterId(value);
                            }else{
                                deviceErrorList.add(row);
                                loop = false;
                            }
                            break;
                        default:
                            break;
                    }
                }
//				validParamRequired(device);
//				validParamFormat(device);
                if (loop) {
                    // 设置租户id
                    device.setTenantId(tenantId);
                    device.setCreateTime(date);
                    device.setUpdateTime(date);
                    devices.add(device);
                }
            } catch (Exception e) {
                deviceErrorList.add(row);
                continue;
            }
        }
        return devices;
    }

    /**
     * 查询电表是否已被绑定
     * @param wattmeterId
     * @param tenantId
     * @return
     */
    private Integer getWattmeterBindIfExists(String wattmeterId,String tenantId){
        if(wattmeterId == null){
            return null;
        }
        //检查设备表是否存在
        QueryWrapper<Device> qwDevice=new QueryWrapper<>();
        qwDevice.eq("code",wattmeterId);
        qwDevice.eq("tenant_id",tenantId);
        Device device=deviceService.getOne(qwDevice);
        if(device == null){
            return null;
        }
        //检查是否已绑定
        QueryWrapper<AirHostDevice> qw=new QueryWrapper<>();
        qw.eq("tenant_id",tenantId);
        qw.eq("wattmeter_id",wattmeterId);
        int count=baseMapper.selectCount(qw);
        if(count>0){
            return null;
        }
        return count;
    }

    private List<List<String>> getContentList(MultipartFile file) {

        List<List<String>> contentList = ExcelReadUtil
                .getExcelInfo(file, PARSE_EXCEL_START_ROW, null, -1);

        //验证导入文件 是否使用了正确的模板，以及表格第一列是否缺失或多了字段
        Map<Integer, String> standardHeaderRow = new HashMap<>(6);

        String keyValue = "主机编码(必填):deviceId,电表编码(必填):wattmeterId";
        List<String> keys = Arrays.asList(StringUtils.split(keyValue, ",")).stream().map(s -> s = s.substring(0, s.indexOf(":"))).collect(Collectors.toList());
        for (int i = 0; i < keys.size(); i++) {
            standardHeaderRow.put(i, keys.get(i));
        }

        StringUtils.split(",");
        //根据表头判断是否使用了正确的模板
        ExcelReadUtil.validateExeclTemplet(contentList, 0, standardHeaderRow);

        int[] requiredColumnIndexes = {0, 1};

        int errorNum = ExcelReadUtil.validateRequiredFields(contentList, requiredColumnIndexes);
        if (errorNum != -1) {
            throw new RuntimeException("第" + (errorNum + CONTENT_IN_EXCEL_START_ROW) + "行,必填写列为空");
        }
        return contentList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeIds( AirHostDevice airHostDevice){
        Assert.notNull(airHostDevice,"参数为空");
        Assert.notEmpty(airHostDevice.getIds(),"id为空");
        QueryWrapper<AirconditionDevice> deviceQueryWrapper=new QueryWrapper<>();
        String tenantId=linkappUserContextProducer.getNotNullCurrent().getTenantId();
        deviceQueryWrapper.eq("tenant_id",tenantId);
        deviceQueryWrapper.in("host_device_id",airHostDevice.getIds());
        int count=airconditionDeviceService.count(deviceQueryWrapper);
        Assert.isTrue(count<=0,"请先删除主机下设备");
        //删除主机
        QueryWrapper<AirHostDevice> hostqw=new QueryWrapper<>();
        hostqw.eq("tenant_id",tenantId);
        hostqw.in("device_id",airHostDevice.getIds());
        baseMapper.delete(hostqw);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateAirHostDeviceById(AirHostDevice airHostDevice){
        Assert.notNull(airHostDevice,"参数为空");
        Assert.notNull(airHostDevice.getDeviceId(),"deviceId为空");
        String tenantId=linkappUserContextProducer.getNotNullCurrent().getTenantId();

        if(!org.springframework.util.StringUtils.isEmpty(airHostDevice.getWattmeterId())){
            //查询电表是否存在
            QueryWrapper<Device> qwDevice=new QueryWrapper<>();
            qwDevice.eq("code",airHostDevice.getWattmeterId());
            qwDevice.eq("tenant_id",tenantId);
            Device device=deviceService.getOne(qwDevice);
            Assert.isTrue(device!=null,"设备不存在");
            //不是删除,查询电表是否已被绑定
            QueryWrapper<AirHostDevice> qw=new QueryWrapper<>();
            qw.eq("tenant_id",tenantId);
            qw.eq("wattmeter_id",airHostDevice.getWattmeterId()).or().eq("device_id",airHostDevice.getWattmeterId());
            AirHostDevice airHostDevicedb=baseMapper.selectOne(qw);
            if(airHostDevicedb != null){
                Assert.isTrue(false,"设备已被【"+airHostDevicedb.getDeviceId()+"】主机绑定");
            }
        }
        UpdateWrapper<AirHostDevice> uw=new UpdateWrapper();
        uw.set("wattmeter_id",airHostDevice.getWattmeterId());
        uw.eq("tenant_id",tenantId);
        uw.eq("device_id",airHostDevice.getDeviceId());
        baseMapper.update(airHostDevice,uw);
    }
}
